
// some enum-like stuff
MXSETTING_NUM 				= 1;
MXSETTING_STRING 			= 2;
MXSETTING_BOOL 				= 3;


/*------------------------------------
	format bytes into human
	readable form
------------------------------------*/
function util.FormatBytes( size )

	// table of different sizes
	local sizetbl = { "b","kb","mb","gb" };
	
	// format used to return value
	local frmat = "%01.2f %s";
	
	// default word
	local word = "";
	
	// loop through size table
	for k, v in pairs( sizetbl ) do
	
		// update word
		word = v;
		
		// check if size is low enough
		if ( size < 1024 ) then
		
			// break from loop
			break;
			
		else
		
			// divide size
			size = size / 1024;
		
		end
		
	end
	
	// check if we're still using bytes
	if ( word == sizetbl[ 1 ] ) then
	
		// change format
		frmat = "%01d %s";
	
	end
	
	// return formated size
	return frmat:format( size, word );
	
end


/*------------------------------------
	get version from info.txt
------------------------------------*/
function MuseX.GetVersion( )

	// default version
	local version = "(unknown)";

	// path & file to info.txt
	local f = "../addons/musex/info.txt";
	
	// make sure it exists
	if ( !file.Exists( f ) ) then
	
		// return default
		return version;
		
	end
	
	// read the data from file
	local data = file.Read( f ) or "";
	
	// explode each line
	local linetbl = string.Explode( "\n", data );
	
	// loop through each line
	for _, line in pairs( linetbl ) do
	
		// if the line contains "version"
		if ( line:find( "version" ) ) then
		
			// remove the "version" portion
			line = line:sub( 11 );
			
			// find the start and end of the version number
			local s, e = line:find( '(".+")' );
			
			// make sure we found it
			if ( s ) then
			
				// extract version
				version = line:sub( s + 1, e - 1 );
				
			end
			
			// end loop
			break;
		
		end
	
	end
	
	// return version
	return version;

end


/*------------------------------------
	check if vgui object is valid
------------------------------------*/
function MuseX.VGUIValid( )

	// return bool
	return ( MuseX.VGUI && MuseX.VGUI:IsValid() );

end


/*------------------------------------
	initialize settings
	(basically, validate the table)
------------------------------------*/
function MuseX.InitSettings( )

	// current settings version
	local VERSION = 2;

	// check if the settings table exists
	if ( !sql.TableExists( "musex_settings" ) ) then
	
		// if not, create it
		sql.Query( "CREATE TABLE IF NOT EXISTS musex_settings ( key VARCHAR(255), value CLOB );" );
		
		// defaults
		MuseX.SetSetting( "shuffle", 0 );
		MuseX.SetSetting( "repeat", 0 );
		MuseX.SetSetting( "skin", "MuseX" );
		MuseX.SetSetting( "visualization", "none" );
		MuseX.SetSetting( "language", "english" );
		MuseX.SetSetting( "viewmode", "1" );
		
		// store the current settings version
		MuseX.SetSetting( "_settingsversion_", VERSION );
		
	elseif ( MuseX.GetSetting( "_settingsversion_", MXSETTING_NUM ) != VERSION ) then
	
		// clear & reset
		MuseX.ClearSettings();
		
	end
	
	// I used CLOB as the value type because we might store a huge string or something...
	// better safe than sorry
	// also, who really cares? no one loves you, you're adopted, stfu

end


/*------------------------------------
	open language file
------------------------------------*/
function MuseX.LoadLanguage( reload )

	// check prefix
	local pre = ( reload ) && "musex/" || "";

	// build the full language filename
	local langfile = ("%slanguage/%s.lua"):format( pre, MuseX.GetSetting( "language" ) );
	
	// open the language file
	include( langfile );
	
end


/*------------------------------------
	clear the settings table
------------------------------------*/
function MuseX.ClearSettings( )

	// check if the settings table exists
	if ( sql.TableExists( "musex_settings" ) ) then
	
		// if it does, drop it
		sql.Query( "DROP TABLE musex_settings;" )
		
	end
	
	// re-initialize the settings
	MuseX.InitSettings();
	
end


/*------------------------------------
	clear settings command
------------------------------------*/
concommand.Add( "musex_clearsettings", function( pl, cmd, args )

	// call the function, cockfuck
	MuseX.ClearSettings();
	
end );


/*------------------------------------
	get a setting by key
------------------------------------*/
function MuseX.GetSetting( key, t )

	// query the db for the setting
	local result = sql.Query( ("SELECT value FROM musex_settings WHERE key = '%s'"):format( key ) );
	
	// validate the results
	if ( !result ) then
	
		// nothing found, return nothing
		return nil;
		
	end
	
	// get the first result
	result = result[ 1 ][ 'value' ];
	
	// change the type if needed
	if ( t ) then
	
		// integer
		if ( t == MXSETTING_NUM ) then
		
			// convert
			result = tonumber( result );
			
		// string
		elseif ( t == MXSETTING_STRING ) then
		
			// convert
			result = tostring( result );
			
		// boolean
		elseif ( t == MXSETTING_BOOL ) then
		
			// convert
			result = util.tobool( result );
		
		end
	
	end
	
	// return the result
	return result;

end


/*------------------------------------
	save/update a setting by key
------------------------------------*/
function MuseX.SetSetting( key, value )

	// check if the key exists already
	if ( !MuseX.GetSetting( key ) ) then
	
		// if it doesn't, create a new setting
		sql.Query( ("INSERT INTO musex_settings ( key, value ) VALUES ( '%s', '%s' );"):format( tostring( key ), tostring( value ) ) );
	
	else
	
		// otherwise, just update it
		sql.Query( ("UPDATE musex_settings SET value = '%s' WHERE key = '%s'"):format( tostring( value ), tostring( key ) ) );
	
	end

end


/*------------------------------------
	open settings menu
------------------------------------*/
function MuseX.SettingsMenu( compact )

	// close menus
	CloseDermaMenus();
	
	// create the menu
	local menu = DermaMenu();
	
	// create the skin submenu
	local skinmenu = menu:AddSubMenu( "#musex_optionmenu_skin" );
	
	// create the skin selection submenu
	local skinmenu_select = skinmenu:AddSubMenu( "#musex_optionmenu_select" );
	
	// get the current skin
	local curskin = MuseX.GetSetting( "skin" );
	
	// loop through the list of skins
	for k, v in pairs( MuseX.SkinList ) do
	
		// get the title
		local title = k;
		
		// build the switch function
		local switchfunc = function()
		
			MuseX.SetSetting( "skin", k );
			MuseX.Restart( true );
			
		end
	
		// check if it is the active skin
		if ( k == curskin ) then
		
			// change the title
			title = ("(%s)"):format( k );
			
			// destroy the switch function
			switchfunc = nil;
		
		end
	
		// add to list
		skinmenu_select:AddOption( title, switchfunc );
	
	end
	
	// add a spacer
	skinmenu:AddSpacer();
	
	// add the reload selection
	skinmenu:AddOption( "#musex_optionmenu_reload", function() MuseX.ReloadSkins(); end );
	
	// only enable visualization in non-compact mode
	if ( !compact ) then
	
		// get the visualization name
		local vis = MuseX.GetSetting( "visualization" );
		
		// get visualization table
		local tbl = MuseX.VisualizationList[ vis ];
		
		// create visualization submenu
		local vismenu = menu:AddSubMenu( "#musex_optionmenu_visualization" );
		
		// create visualization selection submenu
		local vismenu_select = vismenu:AddSubMenu( "#musex_optionmenu_select" );
		
		// add the "none" option
		vismenu_select:AddOption( "#musex_optionmenu_visualization_none", function() MuseX.SetSetting( "visualization", "none" ) end );
		
		// add a spacer
		vismenu_select:AddSpacer();
		
		// loop through list of visualizations
		for k, v in pairs( MuseX.VisualizationList ) do
		
			// get the title
			local title = k;
			
			// build the switch function
			local switchfunc = function()
			
				MuseX.SetSetting( "visualization", k );
				MuseX.InitVisualization();
				
			end
		
			// check if it is the active visualization
			if ( k == vis ) then
			
				// change the title
				title = ("(%s)"):format( k );
				
				// destroy the switch function
				switchfunc = nil;
			
			end
		
			// add to list
			vismenu_select:AddOption( title, switchfunc );
		
		end
		
		// add a spacer
		vismenu:AddSpacer();
		
		// check for settings to configure
		if ( tbl && tbl.Settings ) then
		
			// add the settings selection
			vismenu:AddOption( "#musex_optionmenu_visualization_settings", function() MuseX.VGUI:OpenVisualizationSettings(); end );
			
		end
		
		// add the reload selection
		vismenu:AddOption( "#musex_optionmenu_reload", function() MuseX.LoadVisualizations(); end );
	
	end
	
	// create hotkey submenu
	local keymenu = menu:AddSubMenu( "#musex_optionmenu_hotkeys" );
	
	// add the edit selection
	keymenu:AddOption( "#musex_optionmenu_hotkeys_edit", function() MuseX.VGUI:OpenHotKeyEditor(); end );
	
	// find language files
	local files = file.FindInLua( "musex/language/*.lua" );
	
	// get the current language
	local curlang = MuseX.GetSetting( "language" );
	
	// create the language submenu
	local langmenu = menu:AddSubMenu( "#musex_optionmenu_language" );
	
	// loop through files
	for _, f in pairs( files ) do
	
		// get the file name
		local title = f:sub( 1, #f - 4 );
		
		// old name
		local oldname = title;
		
		// check if it is the current language
		if ( title == curlang ) then
		
			// change the title
			title = ("(%s)"):format( title );
		
		end
		
		// add the language selection
		langmenu:AddOption( title, function()
		
			// clear the global variable
			_G[ 'MXLANGMSG' ] = "";
			
			// update the setting
			MuseX.SetSetting( "language", oldname );
			
			// load the new language
			MuseX.LoadLanguage( true );
			
			// print the message
			LocalPlayer():ChatPrint( _G[ 'MXLANGMSG' ] );
			
		end );
	
	end
	
	// open menu
	menu:Open();
	
end


/*------------------------------------
	convert a drive type enum to text
------------------------------------*/
function MuseX.DriveType( int )

	// list of types
	local types = { "Unknown", "Removeable Disk", "Local Disk", "Remote", "CD-ROM", "Ramdisk" };
	
	// return the type
	return ( types[ int ] or "Unknown" );

end


/*------------------------------------
	extract the filename from
	full file path
------------------------------------*/
function MuseX.ExtractFilename( fullfilename )

	// explode the full filename
	local tbl = string.Explode( "\\", fullfilename );
	
	// extract just the song
	return tbl[ #tbl ];

end
